package edu.ccut.saturn.studio.logic.contextaction;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.gef.ui.actions.SelectionAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.pde.internal.ui.editor.JarEntryEditorInput;
import org.eclipse.pde.internal.ui.editor.JarEntryFile;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.ide.IDE;
import java.net.URI;

//import com.sun.org.apache.xerces.internal.util.URI;

import edu.ccut.saturn.studio.component.editor.ComponentFileEditor;
import edu.ccut.saturn.studio.core.search.SaturnFileSearcher;
import edu.ccut.saturn.studio.core.util.eclipse.Messages;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnBundleUtil;
import edu.ccut.saturn.studio.logic.model.Shape;
import edu.ccut.saturn.studio.logic.model.ShapesDiagram;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnActionNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnComponentNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnLogicNode;
import edu.ccut.saturn.studio.logic.model.xml.FileParseUtils;
import edu.ccut.saturn.studio.logic.parts.ShapeEditPart;

public class OpenLogicAction extends SelectionAction {
	public static final String ERROR = Messages.getString("OpenLogicAction.error");  //$NON-NLS-1$
	public static final String KEY_VALUE_ERROR = Messages.getString("OpenLogicAction.failedopenfile");  //$NON-NLS-1$
	public static final String ACTION_OPEN_MODEL = "open"; 
	public static final String EDITOR_LOGIC_TYPE = "Logic Editor"; 
	public static final String EDITOR_ACTION_TYPE = "Action Editor"; 
	// "org.eclipse.jdt.ui.CompilationUnitEditor";
	public static final String EDITOR_COMPONENT_TYPE = ComponentFileEditor.SATURN_COMPONENT_FILE_EDITOR;//"com.saturn.saturncomponents.editor"; 
	public static final String CLASSPATHENTRY = "classpathentry"; 
	public static final String KIND_NODE = "kind"; 
	public static final String SRC_NODE = "src"; 
	public static final String PATH_NODE = "path"; 
	private Shape shape;
	private String key;
	@SuppressWarnings("unused")
	private IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
	private final static String SETPARATOR = System.getProperty("file.separator"); 

	public OpenLogicAction(IWorkbenchPart part) {
		super(part);
		setId(OpenLogicAction.ACTION_OPEN_MODEL);
		setText(Messages.getString("OpenLogicAction.openfile"));   //$NON-NLS-1$
	}

	@SuppressWarnings("unchecked")
	protected boolean calculateEnabled() {
		List<Object> objects = this.getSelectedObjects();
		for (Object object : objects) {
			if (object instanceof ShapeEditPart) {
				ShapeEditPart ss = (ShapeEditPart) object;
				this.shape = (Shape) ss.getModel();
				if (this.shape instanceof SaturnLogicNode) {
					this.key = ((SaturnLogicNode) this.shape).getKey();
					return true;
				}
				if (this.shape instanceof SaturnActionNode) {
					this.key = ((SaturnActionNode) this.shape).getKey();
					return true;
				}
				if (this.shape instanceof SaturnComponentNode) {
					this.key = ((SaturnComponentNode) this.shape).getKey();
					return true;
				}
			}
		}
		return false;
	}

	public void run() {
		openfactory(this.shape);
	}

	private void openfactory(Shape shape) {
		if (shape instanceof SaturnLogicNode) {
			openCommand(key, "logic", EDITOR_LOGIC_TYPE); 
		}
		if (shape instanceof SaturnActionNode) {
			openCommand(key, "action", EDITOR_ACTION_TYPE); 
		}
		if (shape instanceof SaturnComponentNode) {
			openCommand(key, "component", EDITOR_COMPONENT_TYPE); 
		}
	}

	/**
	 * 打开jar包中的文件
	 * 
	 * @param jarFile
	 * @param filename
	 * @param page
	 * @param editorId
	 */
	@SuppressWarnings("restriction") 
	private void openFileInjar(JarFile jarFile, String filename,
			IWorkbenchPage page, String editorId) {
		Enumeration<?> jarEntries = jarFile.entries();
		while (jarEntries.hasMoreElements()) {
			JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
			if (jarEntry.getName().equals(filename.substring(1))) {
				JarEntryFile jarEntryFile = new JarEntryFile(jarFile, jarEntry
						.getName());
				IEditorInput input = new JarEntryEditorInput(jarEntryFile);
				if (input != null) {
					try {
						IDE.openEditor(page, input, editorId);
					} catch (PartInitException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * 打开文件
	 * 
	 * @param fullkey
	 *            組件的key值
	 * @param suffix
	 *            文件類型
	 * @param editorId
	 *            編輯器的id
	 */
	// TODO:判断该组件是否在本工程中（1.看是否在src下 ：：2是否在lib下）
	private void openCommand(String fullkey, String suffix, String editorId) {
		IProject project = this.shape.findTheProject();
		if(fullkey==null||fullkey.equals("")||fullkey.indexOf("::")==-1){  
			MessageDialog.openInformation(null, ERROR, KEY_VALUE_ERROR);  
			return;
		}
		String entry[] = fullkey.split("::"); 
		if(OpenEditor(project,entry,suffix,editorId)){
			return;
		}
		IProject projects [] = ResourcesPlugin.getWorkspace().getRoot().getProjects();
		for(IProject ps : projects){
			if(ps.equals(project)){
				continue;
			}
			if(OpenEditor(ps,entry,suffix,editorId)){
				return;
			}
		}
		
		MessageDialog.openInformation(null, ERROR, KEY_VALUE_ERROR);  
	}
	
	private IProject isProject(IProject project,String keyPart1,String keyPart2){
		String projectPath = project.getLocation().toOSString();
		String mfPath = projectPath.concat("/META-INF/MANIFEST.MF"); 
		List<String> srcs = new ArrayList<String>();
		srcs = SaturnFileSearcher.getClasspathInfo(project, "src"); 
		for(String src : srcs){
			String filePath = projectPath +"/"+src+keyPart2; 
			String bundel = FileParseUtils.getParseStr(mfPath,"Bundle-SymbolicName"); 
			if(keyPart1.equals(bundel)&&new File(filePath).exists()){
				return project;
			}
		}
		return null;
	}
	
	private boolean OpenEditor(IProject project,String [] entry,String suffix ,String editorId){
		if(((isProject(project, entry[0], entry[1])))!=null){
			opensrcfile(project, suffix, editorId, entry[1]);
			return true;
		}else{
			if(isProjectJar(project,entry[0],entry[1])!=null){
				JarFile jarFile =isProjectJar(project,entry[0],entry[1]);
				openFileInjar(jarFile, entry[1],((ShapesDiagram) shape.getParent()).getEditor().getEditorSite().getPage(), editorId);
				return true;
			}
		}
		return false;
	}
	
	private JarFile isProjectJar(IProject project ,String keyPart1,String keyPart2){
		List<JarFile> jars = this.getJarResource(project);
		  int i = keyPart2.lastIndexOf("/"); 
		  String fileName = keyPart2.substring(i+1);
		for(JarFile jar : jars){
//			String s = ParseBundleSymbolicName.getBundleSybolicNameFromJar(jar, "Bundle-SymbolicName"); 
			String s = null;
			try {
				s = SaturnBundleUtil.getBundleSymbolicName(jar);
			} catch (Exception e) {
				e.printStackTrace();
			} 
			if(keyPart1.equals(s)&&isContainsFileInJar(jar,fileName)){
				return jar;
			}
		}
		return null;
	}
	
	private boolean isContainsFileInJar(JarFile jar,String fileName){
		Enumeration<?> jarEntries = jar.entries();
		while (jarEntries.hasMoreElements()) {
			ZipEntry ze = (ZipEntry) jarEntries.nextElement();
			if(ze.getName().contains(fileName)){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 打开指定工程内的src下的组件
	 * 
	 * @param suffix
	 *            文件类型
	 * @param editorId
	 *            编辑器id
	 * @param project
	 *            指定的工程
	 * @param keypath
	 *            将fullkey拆分的数组后的src下的路径
	 */
	private void opensrcfile(IProject project, String suffix, String editorId,
			String keypath) {
		// TODO:把所有的key搜索到，然后对比
		List<String> srcs = new ArrayList<String>();
		srcs = SaturnFileSearcher.getClasspathInfo(project, "src"); 
		for (String src : srcs) {
			String projectSrcPath = project.getLocation().toOSString() + SETPARATOR + src;
			String[] srcfiles = this.getFilePathsFromClasspath(
					projectSrcPath, suffix);
			for (int i = 0; i < srcfiles.length; i++) {
				String[] srcPath = srcfiles[i].split(src);
				if (srcPath[1].trim().equals(keypath.trim())) {
					IFile ifile = ResourcesPlugin.getWorkspace().getRoot()
							.getFileForLocation(
									new org.eclipse.core.runtime.Path(
											srcfiles[i]));
					try {
						IDE.openEditor(((ShapesDiagram) shape.getParent())
								.getEditor().getEditorSite().getPage(), ifile,
								editorId);
					} catch (PartInitException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	public static String[] getFilePathsFromClasspath(String directory, String suffix) {
		File rootFile = null;
		
		URI classpath = getClasspath();
		
		//如果directory无效,以classpath为根路径
		if (directory == null || directory.trim().equals("")) {
			rootFile = new File(classpath.getPath());
		} else {
			rootFile = new File(classpath.getPath() + System.getProperty("file.separator") + directory);
		
			if (!rootFile.exists()) {
				throw new IllegalArgumentException("In classpath: didn't have a directory path is: " + directory);
			}
		}
		
		LinkedList<File> files = new LinkedList<File>();
		files.addLast(rootFile);
		
		List<String> availedFilePath = new LinkedList<String>();
		while (!files.isEmpty()) {
			File file = files.removeFirst();
			
			if (file.isDirectory()) {
				File[] subFiles = file.listFiles();
				for (int i = 0; i < subFiles.length; ++i) {
					files.add(subFiles[i]);
				}
				
				continue;
			}
			
			if (file.getName().endsWith(suffix)) {
				availedFilePath.add(file.getAbsolutePath().replace(System.getProperty("file.separator"), "/").replace(classpath.getPath().substring(1), ""));
			}
		}
		
		return availedFilePath.toArray(new String[availedFilePath.size()]);
	}
	
	
	
	public static URI getClasspath() {
		URI classpath = null;
		
		try {
			classpath = Thread.currentThread().getContextClassLoader().getResource("").toURI();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		
		return classpath;
	}

	private List<JarFile> getJarResource(IProject project) {
		List<String> libs = null;
		List<JarFile> jars = new ArrayList<JarFile>();
		libs = SaturnFileSearcher.getClasspathInfo(project, "lib"); 
		for (String lib : libs) {
			String projectLibPaths = (project.getLocation().toString()
					+ SETPARATOR + lib).replace("/", SETPARATOR); 
			File jar = new File(projectLibPaths);
			try {
				JarFile jarFile = new JarFile(jar);
				jars.add(jarFile);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return jars;
	}
}
